package com.sun.showcase.excel;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
public abstract class AbstractExcelExportTemplate<T> implements ExcelExportTemplate<T>{
	/**
	 * 默认列宽
	 */
	private static final int DEFAULT_COLUMN_WIDTH = 4000;
	/**
	 * excel
	 */
	protected Workbook  workbook;
	/**
	 * excel
	 */
	protected List<Sheet> sheets = new ArrayList<Sheet>();

	protected String[][] titles;
	
	protected CellStyle captionRowSytle;

	protected CellStyle titleRowStyle;

	protected CellStyle bodyRowStyle;

	protected Map<Integer, Boolean> hasCaptionMap = new HashMap<Integer, Boolean>();

	protected int columnWidth = DEFAULT_COLUMN_WIDTH;

	protected T parameters;


	@Override
	public void doExport(OutputStream outputStream,T parameters) throws IOException {
		String[] sheetNames = this.getSheetNames();
		Validate.notEmpty(sheetNames);
		Validate.notNull(outputStream);
		this.parameters = parameters;
		this.workbook = new SXSSFWorkbook(getRowAccessWindowSize());
		this.titles = this.getTitles();
		this.captionRowSytle = crateCaptionCellStyle();
		this.titleRowStyle = crateTitleCellStyle();
		this.bodyRowStyle = crateBodyCellStyle("left"); //默认居左
		this.afterCreateWorkBook();
		
		for (int i = 0; i < sheetNames.length; i++) {
			Sheet sheet = workbook.createSheet(sheetNames[i]);
			this.sheets.add(sheet);
			afterBuildSheet(i);
			buildCaption(i);
			buildTitle(i);
			afterBuildTitle(i);
			buildBody(i);
			afterBuildBody(i);
		}
		this.workbook.write(outputStream);
	}
	/**
	 * Excel 表头 样式 设置
	 * @return
	 */
	protected CellStyle crateTitleCellStyle() {
		Font font = workbook.createFont();
		font.setColor(Font.COLOR_NORMAL);
		CellStyle cellStyle = workbook.createCellStyle();
		cellStyle.setWrapText(false); //自动换行
		font.setFontHeight((short)250);
		font.setColor(HSSFColor.BLACK.index); //字体颜色
		cellStyle.setFont(font);
		cellStyle.setFillForegroundColor(IndexedColors.LIGHT_TURQUOISE.index); //背景色
		cellStyle.setFillPattern(CellStyle.SOLID_FOREGROUND);
		short border = 1;
		setCellBorder(cellStyle,border,border,border,border);
		cellStyle.setVerticalAlignment(CellStyle.VERTICAL_CENTER); //垂直居中 
		cellStyle.setAlignment(CellStyle.ALIGN_CENTER); //水平居中
		return cellStyle;
	}
	/**
	 * Excel表体 样式 设置   
	 * 报表格式:数字居右,汉字居左 
	 * @return
	 */
	protected CellStyle crateBodyCellStyle(String align) {
		Font font = workbook.createFont();
		//font.setColor(HSSFColor.BLUE_GREY.index);
		CellStyle cellStyle = workbook.createCellStyle();
		cellStyle.setWrapText(false);
		cellStyle.setFont(font);
		cellStyle.setFillForegroundColor(HSSFColor.WHITE.index);
		cellStyle.setFillPattern(CellStyle.SOLID_FOREGROUND);
		cellStyle.setVerticalAlignment(CellStyle.VERTICAL_CENTER); //垂直居中 
		cellStyle.setAlignment(CellStyle.ALIGN_CENTER); //水平居中  
		if("right".equals(align)){
			cellStyle.setAlignment(CellStyle.ALIGN_RIGHT);
		}
		if("left".equals(align)){
			cellStyle.setAlignment(CellStyle.ALIGN_LEFT);
		}
		short border = 1;
		setCellBorder(cellStyle,border,border,border,border);
		return cellStyle;
	}
	/**
	 * Excel表体 样式 设置   第一行为合计
	 * 报表格式:数字居右,汉字居左 
	 * @return
	 */
	protected CellStyle crateBodyCellStyleHj(String align,String count) {
		Font font = workbook.createFont();			
		CellStyle cellStyle = workbook.createCellStyle();
		cellStyle.setWrapText(false);
		cellStyle.setFont(font);
		cellStyle.setFillForegroundColor(HSSFColor.WHITE.index);
		cellStyle.setFillPattern(CellStyle.SOLID_FOREGROUND);
		cellStyle.setVerticalAlignment(CellStyle.VERTICAL_CENTER); //垂直居中 
		cellStyle.setAlignment(CellStyle.ALIGN_CENTER); //水平居中  
		if("合计".equals(count)){
			cellStyle.setFillForegroundColor(HSSFColor.PALE_BLUE.index);
		}if("A区".equals(count)){
			cellStyle.setFillForegroundColor(HSSFColor.GREEN.index);
		}if("B区".equals(count)){
			cellStyle.setFillForegroundColor(HSSFColor.BLUE.index);
		}if("C区".equals(count)){
			cellStyle.setFillForegroundColor(HSSFColor.YELLOW.index);
		}if("D区".equals(count)){
			cellStyle.setFillForegroundColor(HSSFColor.RED.index);
		}if("right".equals(align)){
			cellStyle.setAlignment(CellStyle.ALIGN_RIGHT);
		}if("left".equals(align)){
			cellStyle.setAlignment(CellStyle.ALIGN_LEFT);
		}
		short border = 1;
		setCellBorder(cellStyle,border,border,border,border);
		return cellStyle;
	}
	
	/**
	 * 表头合并
	 * @param sheetIndex
	 */
	protected void buildTitle(int sheetIndex){
		if(this.titles.length < sheetIndex + 1){
			return;
		}
		String[] ts = this.titles[sheetIndex];
		if(ts == null){
			return;
		}
		Sheet sheet = this.getSheet(sheetIndex);
		int titleStartIndex = this.getTitleStartIndex(sheetIndex);
		Row rowTitle = sheet.createRow(titleStartIndex); 
		for(int i = 0; i < ts.length; i++){
			sheet.setColumnWidth(i, columnWidth);
			createStyledCell(rowTitle, i, ts[i], this.titleRowStyle);
		}
	}

	protected void createStyledCell(Row row,int index,String cellValue,CellStyle cellStyle){
		Cell cell = row.createCell(index);
		cell.setCellValue(cellValue);
		cell.setCellStyle(cellStyle);
	}
	protected void createStyledCell(Row row,int index,String cellValue){
		Cell cell = row.createCell(index);
		cell.setCellValue(cellValue);
	}
	protected void createStyledCell(Row row,int index,Double cellValue){
		Cell cell = row.createCell(index);
		cell.setCellValue(cellValue);
	}
	protected void createStyledCell(Row row,int index,Integer cellValue){
		Cell cell = row.createCell(index);
		cell.setCellValue(cellValue);
	}
	
	protected void afterCreateWorkBook(){
	}

	protected CellStyle crateCaptionCellStyle() {
		Font font = workbook.createFont();
		font.setColor(Font.COLOR_NORMAL);
		CellStyle cellStyle = workbook.createCellStyle();
		cellStyle.setWrapText(false);
		font.setFontHeight((short)250);
		cellStyle.setFont(font);
		cellStyle.setFillForegroundColor(IndexedColors.BLUE_GREY.index);
		cellStyle.setFillPattern(CellStyle.SOLID_FOREGROUND);
		cellStyle.setAlignment(CellStyle.ALIGN_CENTER);
		return cellStyle;
	}
		

	protected void setCellBorder(CellStyle cellStyle,short top,short bottom,short left,short right){
		cellStyle.setBorderBottom(bottom);
		cellStyle.setBorderLeft(left);
		cellStyle.setBorderRight(right);
		cellStyle.setBorderTop(top);
	}
	

	protected Sheet getSheet(int sheetIndex) {
		return this.sheets.get(sheetIndex);
	}


	protected void afterBuildSheet(int sheetIndex) {
	}
	

	protected void buildCaption(int sheetIndex){
		Sheet sheet = getSheet(sheetIndex);
		String[] captions = this.getCaptions(); 
		hasCaptionMap.put(sheetIndex, false);
		if(captions != null && captions.length >=sheetIndex +1){
			String caption = captions[sheetIndex];
			if(StringUtils.isNotBlank(caption)){
				Row row = sheet.createRow(0);
				int lastColumn = calculateLastColumn(sheetIndex);
				CellRangeAddress cellRangeAddress = new CellRangeAddress(0, 0, 0, lastColumn);
				sheet.addMergedRegion(cellRangeAddress);
				createStyledCell(row, 0, caption, this.captionRowSytle);
				hasCaptionMap.put(sheetIndex, true);
			}
		}
	}
	

	protected int calculateLastColumn(int sheetIndex){
		if(this.titles != null && sheetIndex <= this.titles.length -1 && this.titles[sheetIndex] != null){
			return this.titles[sheetIndex].length - 1;
		}else{
			return 1;
		}
	}
	
	protected int getBodyStartIndex(int sheetIndex){
		int captionRow = getTitleStartIndex(sheetIndex);;
		int titleRow = 0;
		if(this.titles != null && this.titles.length >= sheetIndex + 1){
			if(titles[sheetIndex] != null && titles[sheetIndex].length >0){
				titleRow = 1;
			}
		}
		return captionRow + titleRow;
	}

	protected int getTitleStartIndex(int sheetIndex){
		return this.hasCaptionMap.get(sheetIndex) ? 1 : 0;
	}

	protected void afterBuildTitle(int sheetIndex) {
	}


	protected abstract void buildBody(int sheetIndex);

	protected void afterBuildBody(int sheetIndex) {
	}

	@Override
	public String[] getCaptions() {
		return new String[]{};
	}

	@Override
	public int getRowAccessWindowSize() {
		return 200;
	}
}

